!--------------------------------
! Programa dedicado a calcular
! o determinante de uma matriz
! dada.
!
! Programa compilado e testado com:
! $ gfortran -o exec04 exec04.f90
! $ ./exec03
! 
! Forma de utilizacao auto-explicativa
! atravez de comentarios.
!
! _o_o_ oOo _o_o_ 17/09/2010

PROGRAM exec04
  IMPLICIT NONE

  INTERFACE 
    FUNCTION Factorial(n)
      INTEGER :: Factorial
      INTEGER, INTENT(IN) :: n
    END FUNCTION Factorial
  END INTERFACE

  INTEGER, DIMENSION(10000,7) :: perms_old ! As permutacoes antigas
  INTEGER, DIMENSION(10000,8) :: perms_new ! As novas permutacoes
  REAL, DIMENSION(8,8) :: matrix
  REAL :: det, foo
  INTEGER :: NN, N, i, j, apont, fact ! Numero de elementos, iterador

  write(*,*) "qual N da matriz (N x N)?"
  read(*,*) NN
  ! fact = Factorial(NN)
  ! write(*,*) fact

  IF (NN<=1) THEN
      write(*,*) "Ok, determinante de matriz de 1 elemento eh o elemento"
      STOP
  END IF
  write(*,*) "Fazendo as N! permutacoes necessarias."
  perms_old(1,1:3)=[1,2,1]
  perms_old(2,1:3)=[2,1,-1]

!   write(*,*) perms_old(1,1:3)
!   write(*,*) perms_old(2,1:3)

!   open(unit=10,file="perm_out.dat")
  write(*,*) "Fazendo novas permutacoes"
  N=2
  DO WHILE (N<NN)
      i=1
      fact=Factorial(N)
      write(*,*) "*********novo ciclo!!!!!***"
      DO WHILE (i<=fact)
          apont=1+(i-1)*(N+1)
!           write(*,*) i, apont
          perms_new(apont,1:N)=perms_old(i,1:N)
          perms_new(apont,N+1)=N+1
          perms_new(apont,N+2)=perms_old(i,N+1)
!           write(*,*) perms_new(apont,1:N+2)
!           write(10,*) perms_new(apont,1:N+2)
          j=2
          DO WHILE (j<=N+1)
                perms_new(apont+j-1,1:N)=perms_old(i,1:N) ! copia permutacao
!                 write(*,*) "ok1", perms_new(apont+j-1,1:N)
                perms_new(apont+j-1,N+1-(j-1))=N+1 ! coloca elemento extra
!                 write(*,*) "ok2", perms_new(apont+j-1,1:N+1) 
                perms_new(apont+j-1,N+1)=perms_old(i,N+1-(j-1)) !recoloca
!                 write(*,*) "ok3", perms_new(apont+j-1,1:N+1) 
                perms_new(apont+j-1,N+2)=perms_old(i,N+1)*(-1) ! copia paridade
!                 write(*,*) perms_new(apont+j-1,1:N+2)  
!                 write(10,*) perms_new(apont+j-1,1:N+2)
                j=j+1
          END DO
          i=i+1
      END DO
      i=1
      fact=Factorial(N+1)
      DO WHILE (i<=fact)
          perms_old(i,1:N+2)=perms_new(i,1:N+2)
          i=i+1
      END DO
      N=N+1
  END DO



  !!!!!!!!!!!!!!!!!!!!!!!!!
  ! Lendo a Matriz
  OPEN(11,file='matriz_in.dat')
  i=1
  DO WHILE (i<=NN)
     read(11,*) matrix(i,1:NN)
!      write (*,*) i, "ok"
     i=i+1
  END DO


  !!!!!!!!!!!!!!!1
  ! Calculando o determinante
  fact=Factorial(NN)
  i=1
  det=0
  write(*,*) "iniciando o calculo do det"
  write(*,*) "***variaveis", fact, NN
  DO WHILE (i<=fact)
!       write(*,*) perms_old(i,1:NN+1) ! 
      foo=matrix(1,perms_old(i,1))
      j=2
!       write(*,*) matrix(1,perms_old(i,1))
      DO WHILE (j<=NN)
!           write(*,*) matrix(j,perms_old(i,j))          
          foo=foo*matrix(j,perms_old(i,j))
          j=j+1
      END DO
!       write(*,*) perms_old(i,j)
      foo=foo*perms_old(i,j)
      det = det + foo
      i=i+1
  END DO
  write(*,*) det
end PROGRAM

!-----Factorial------------------------------------------------------
!
!  Function to calculate factorials resursively
!
!---------------------------------------------------------------------
RECURSIVE FUNCTION Factorial(n)  RESULT(Fact)

IMPLICIT NONE
INTEGER :: Fact
INTEGER, INTENT(IN) :: n

  IF (n == 0) THEN
    Fact = 1
  ELSE
    Fact = n * Factorial(n-1)
  END IF

END FUNCTION Factorial
